package cn.tedu.qxhouserent.house.service.impl;

import cn.tedu.qxhouserent.commons.ex.ServiceException;
import cn.tedu.qxhouserent.commons.pojo.vo.PageData;
import cn.tedu.qxhouserent.commons.web.ServiceCode;
import cn.tedu.qxhouserent.house.mapper.HouseMapper;
import cn.tedu.qxhouserent.house.mapper.SectionMapper;
import cn.tedu.qxhouserent.house.pojo.entity.House;
import cn.tedu.qxhouserent.house.pojo.entity.Section;
import cn.tedu.qxhouserent.house.pojo.param.SectionAddNewParam;
import cn.tedu.qxhouserent.house.pojo.param.SectionUpdateInfoParam;
import cn.tedu.qxhouserent.house.pojo.vo.*;
import cn.tedu.qxhouserent.house.service.SectionService;
import cn.tedu.qxhouserent.commons.util.PageInfoToPageDataConverter;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.*;


@Slf4j
@Service
public class SectionServiceImpl implements SectionService {

    @Autowired
    SectionMapper sectionMapper;
    @Autowired
    HouseMapper houseMapper;

    @Override
    public void addNew(SectionAddNewParam sectionAddNewParam) {
        log.debug("开始处理【添加区域】的业务，参数：{}", sectionAddNewParam);
        // 检查地名是否被占用,如果被占用,则抛出异常
        QueryWrapper<Section> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("name", sectionAddNewParam.getName())
                .eq("parent_id", sectionAddNewParam.getParentId());
        Integer countByName = sectionMapper.selectCount(queryWrapper);
        log.debug("根据地名统计匹配的区域数量，结果：{}", countByName);
        if (countByName > 0){
            String message = "添加区域失败,地名已经被占用!";
            log.warn(message);
            throw new ServiceException(ServiceCode.ERR_CONFLICT, message);
        }
        //预设深度为1即最高级
        Integer depth = 1;
        SectionStandardVO sectionStandardVO = null;
        //判断父级id是否为0
        if (sectionAddNewParam.getParentId() != 0) {
            sectionStandardVO = sectionMapper.getStandardById(sectionAddNewParam.getParentId());
            if (sectionStandardVO == null){
                String message = "添加类别失败,父级类别不存在!";
                log.warn(message);
                throw new ServiceException(ServiceCode.ERR_CONFLICT, message);
            } else {
                depth = sectionStandardVO.getDepth() + 1;
            }
        }

        Section section = new Section();
        BeanUtils.copyProperties(sectionAddNewParam,section);
        section.setDepth(depth);
        section.setIsDisplay(0);
        log.debug("准备将新的区域名数据写入到数据库，数据：{}", section);
        int insert = sectionMapper.insert(section);
        if (insert != 1) {
            String message = "添加失败，服务器忙，请稍后再试！";
            log.warn(message);
            throw new ServiceException(ServiceCode.ERR_INSERT, message);
        }

        //判断父级ID是不为0且父级类的是否为父级的属性是否为0
        if (sectionAddNewParam.getParentId() != 0 && sectionStandardVO.getIsParent() == 0){
            //判断成立,将父级类别的是否为父级的属性改为1
            Section updateSection = new Section();
            updateSection.setId(sectionStandardVO.getId());
            updateSection.setParent_id(1L);
            int rows = sectionMapper.updateById(updateSection);
            if (rows != 1) {
                String message = "添加区域失败,服务器正忙,请稍后再试!";
                log.warn(message);
                throw new ServiceException(ServiceCode.ERR_UPDATE, message);
            }
        }
        log.debug("将新的区域数据写入到数据库，完成！");
    }

    @Override
    public void deleteById(Long id) {
        log.debug("开始处理【根据ID删除区域】的业务，参数：{}", id);
        // 检查该区域是否存在，如果不存在，则抛出异常
        QueryWrapper<Section> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("id", id);
        int countById = sectionMapper.selectCount(queryWrapper);
        log.debug("根据区域ID统计匹配的区域数量，结果：{}", countById);
        if (countById == 0) {
            String message = "删除区域失败，该数据不存在！";
            log.warn(message);
            throw new ServiceException(ServiceCode.ERR_NOT_FOUND, message);
        }

        //检查是否有区域的parent_id 为 该id
        QueryWrapper<Section> queryWrapper1 = new QueryWrapper<>();
        queryWrapper1.eq("parent_id", id)
                .ne("id", id);
        int countById1 = sectionMapper.selectCount(queryWrapper1);
        log.debug("根据区域ID统计匹配parent_id的区域数量，结果：{}", countById1);
        if (countById1 != 0) {
            String message = "删除区域失败，仍有区域关联！";
            log.warn(message);
            throw new ServiceException(ServiceCode.ERR_CONFLICT, message);
        }

        //检查house有没有关联
        QueryWrapper<House> houseQueryWrapper = new QueryWrapper<>();
        houseQueryWrapper.eq("section_id", id);
        Integer integer = houseMapper.selectCount(houseQueryWrapper);
        log.debug("根据区域ID统计匹配house数量，结果：{}", integer);
        if (integer != 0) {
            String message = "删除区域失败，仍有房源关联！";
            log.warn(message);
            throw new ServiceException(ServiceCode.ERR_CONFLICT, message);
        }

        SectionStandardVO sectionStandardVo = sectionMapper.getStandardById(id);
        if (sectionStandardVo.getIsParent() == 1){
            String message = "删除区域失败,该区域仍包含有子类";
            log.warn(message);
            throw new ServiceException(ServiceCode.ERR_CONFLICT, message);
        }

        //开始删除
        int i = sectionMapper.deleteById(id);
        if (i != 1) {
            String message = "删除失败，服务器忙，请稍后再试！";
            log.warn(message);
            throw new ServiceException(ServiceCode.ERR_DELETE, message);
        }

        //通过父类ID查询要删除的数据的父类是否还有子类
        Integer countByParentId = sectionMapper.countByPrentId(sectionStandardVo.getParentId());
        if (countByParentId == 0){
            Section section = new Section();
            section.setId(sectionStandardVo.getParentId());
            section.setIs_parent(0);
            int rows = sectionMapper.updateById(section);
            if (rows != 1) {
                String message = "删除区域详情失败，服务器忙，请稍后再尝试！";
                log.warn(message);
                throw new ServiceException(ServiceCode.ERR_UPDATE, message);
            }
        }


        log.debug("删除成功！");
    }

    @Override
    public void updateById(Long id, SectionUpdateInfoParam sectionUpdateInfoParam) {
        log.debug("开始处理【修改区域】的业务，ID：{}, 新数据：{}", id, sectionUpdateInfoParam);
        // 检查区域是否存在，如果不存在，则抛出异常
        QueryWrapper<Section> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("id", id);
        int countById = sectionMapper.selectCount(queryWrapper);
        log.debug("根据区域ID统计匹配的区域数量，结果：{}", countById);
        if (countById == 0) {
            String message = "修改区域信息失败，区域数据不存在！";
            log.warn(message);
            throw new ServiceException(ServiceCode.ERR_NOT_FOUND, message);
        }

        //检查parent_id是否存在，如果为0 则不用判断
        if (sectionUpdateInfoParam.getParentId() != 0) {
            log.debug("查看修改的parent_id是否存在");
            QueryWrapper<Section> queryWrapper1 = new QueryWrapper<>();
            queryWrapper1.eq("id", sectionUpdateInfoParam.getParentId())
                    .ne("id", id);
            Integer countById1 = sectionMapper.selectCount(queryWrapper1);
            log.debug("根据parent_id统计匹配的区域数量，结果：{}", countById1);
            if (countById1 == 0){
                String message = "修改区域失败,父级id不存在!";
                log.warn(message);
                throw new ServiceException(ServiceCode.ERR_NOT_FOUND,message);
            }
        }

        //判断区域名是否被占用
        QueryWrapper<Section> queryWrapper2 = new QueryWrapper<>();
        queryWrapper2.eq("name", sectionUpdateInfoParam.getName())
                .eq("parent_id", sectionUpdateInfoParam.getParentId());
        Integer countByName = sectionMapper.selectCount(queryWrapper2);
        log.debug("根据地名统计匹配的区域数量，结果：{}", countByName);
        if (countByName > 0){
            String message = "修改区域失败,地名已经被占用!";
            log.warn(message);
            throw new ServiceException(ServiceCode.ERR_CONFLICT, message);
        }

        //如果层级为1 父级id必须为零
        if (sectionUpdateInfoParam.getDepth() == 1) {
            if (sectionUpdateInfoParam.getParentId() != 0) {
                String message = "层级为1，父级id必须为零";
                log.warn(message);
                throw new ServiceException(ServiceCode.ERR_CONFLICT, message);
            }
        }

        //如果父级id为0 层级必须为1
        if (sectionUpdateInfoParam.getParentId() == 0) {
            if (sectionUpdateInfoParam.getDepth() != 1) {
                String message = "父级id为0 层级必须为1";
                log.warn(message);
                throw new ServiceException(ServiceCode.ERR_CONFLICT, message);
            }
        }

        // 执行修改
        log.debug("检查通过，开始修改！");
        Section section = new Section();
        BeanUtils.copyProperties(sectionUpdateInfoParam, section);
        section.setId(id);
        int i = sectionMapper.updateById(section);
        if (i != 1) {
            String message = "更新失败，服务器忙，请稍后再试！";
            log.warn(message);
            throw new ServiceException(ServiceCode.ERR_UPDATE, message);
        }
        log.debug("将新的区域数据更新到数据库，完成！");
    }

    @Override
    public void setDisplay(Long id) {
        log.debug("开始处理【将区域显示在导航栏】的业务，参数：{}", id);
        updateDisplayById(id, 1);
    }

    @Override
    public void setHidden(Long id) {
        log.debug("开始处理【将区域不显示在导航栏】的业务，参数：{}", id);
        updateDisplayById(id, 0);
    }

    private void updateDisplayById(Long id, Integer isDisplay) {
        // 调用Mapper对象的getStandardById()方法执行查询
        SectionStandardVO currentSection = sectionMapper.getStandardById(id);
        // 判断查询结果是否为null，如果是，则抛出异常
        if (currentSection == null) {
            String message = DISPLAY_TEXT[isDisplay] + "区域失败，区域数据不存在！";
            log.warn(message);
            throw new ServiceException(ServiceCode.ERR_NOT_FOUND, message);
        }

        // 判断查询结果中的isDisplay与参数isDisplay是否相同，如果是，则抛出异常（当前状态与目标状态相同，没必要执行更新）
        if (currentSection.getIsDisplay() == isDisplay) {
            String message = DISPLAY_TEXT[isDisplay] + "区域失败，此类别已经处于" + DISPLAY_TEXT[isDisplay] + "状态！";
            log.warn(message);
            throw new ServiceException(ServiceCode.ERR_CONFLICT, message);
        }

        // 创建Category对象
        Section updateSection = new Section();
        // 向Category对象中封装属性值：id, isDisplay，均来自方法参数
        updateSection.setId(id);
        updateSection.setIsDisplay(isDisplay);
        // 调用Mapper对象的update()方法执行更新
        int rows = sectionMapper.updateById(updateSection);
        if (rows != 1) {
            String message = DISPLAY_TEXT[isDisplay] + "区域失败，服务器忙，请稍后再尝试！";
            log.warn(message);
            throw new ServiceException(ServiceCode.ERR_UPDATE, message);
        }
    }

    @Override
    public SectionStandardVO getStandardById(Long id) {
        log.debug("开始处理【根据ID查询区域】的业务，参数：{}", id);
        SectionStandardVO queryResult = sectionMapper.getStandardById(id);
        if (queryResult == null) {
            String message = "查询区域失败，数据不存在！";
            log.warn(message);
            throw new ServiceException(ServiceCode.ERR_NOT_FOUND, message);
        }
        return queryResult;
    }

    @Override
    public PageData<SectionListItemVO> listByParentId(Long parentId,Integer pageNum) {
        Integer pageSize = 9;
        return listByParentId(parentId,pageNum,pageSize);
    }

    @Override
    public PageData<SectionListItemVO> listByParentId(Long parentId,Integer pageNum,Integer pageSize) {
        log.debug("开始处理【查询区域列表】的业务，页码：{}，每页记录数：{}", pageNum, pageSize);
        PageHelper.startPage(pageNum, pageSize);
        List<SectionListItemVO> list = sectionMapper.listByParentId(parentId);
        PageInfo<SectionListItemVO> pageInfo = new PageInfo<>(list);
        PageData<SectionListItemVO> pageData = PageInfoToPageDataConverter.convert(pageInfo);
        log.debug("查询完成，即将返回：{}", pageData);
        return pageData;
    }

    @Override
    public List<SectionTreeItemVO> listTree() {
        log.debug("开始处理区域树业务,参数,无");
        List<SectionTreeItemVO> sectionTree = new ArrayList<>();

        List<SectionListItemVO> sectionList = sectionMapper.list();

        Map<Long,SectionListItemVO> allSectionMap = transformListToMap(sectionList);
        for (Long key : allSectionMap.keySet()){
            SectionListItemVO mapItem = allSectionMap.get(key);
            //判断每个类别对象是否还有父类
            if (mapItem.getParentId() == 0){
                //如果没有父类,将类别对象的id和name装进CategoryTreeItemVO对象中,并将对象装进集合中
                SectionTreeItemVO sectionTreeItemVO = convertListItemToTreeItem(mapItem);
                sectionTree.add(sectionTreeItemVO);

                fillChidren(mapItem,sectionTreeItemVO,allSectionMap);
            }

        }
        return sectionTree;
    }

    //从查出来的所有类别信息进行遍历装进map中
    private Map<Long,SectionListItemVO> transformListToMap(List<SectionListItemVO> sectionList){
        Map<Long,SectionListItemVO> sectionMap = new LinkedHashMap<>();
        //遍历传来的区域对象参数,装进map里
        for (SectionListItemVO sectionListItemVO : sectionList){
            sectionMap.put(sectionListItemVO.getId(), sectionListItemVO);
        }

        return sectionMap;
    }

    private void fillChidren(SectionListItemVO listItem,SectionTreeItemVO currentTreeItem, Map<Long,SectionListItemVO> allSectionMap){
        //判断类别对象是否为父类
        if (listItem.getIsParent() == 1){
            //当这个对象是父类时,遍历map获取每个类别对象
            currentTreeItem.setChildren(new ArrayList<>());
            Set<Long> keySet = allSectionMap.keySet();
            for (Long key : keySet) {
                SectionListItemVO mapItem = allSectionMap.get(key);
                //如果遍历得到的对象的父类ID是参数类别对象ID(即参数类别对象是遍历类别对象的父类时)
                if (mapItem.getParentId() == listItem.getId()) {
                    //将遍历对象的id,name装进CategoryTreeItemVO对象
                    SectionTreeItemVO sectionTreeSubItemVO = convertListItemToTreeItem(mapItem);
                    //将遍历对象装进传来的CategoryTreeItemVO对象的子类集合
                    currentTreeItem.getChildren().add(sectionTreeSubItemVO);
                    //如果遍历对象依旧是父类,则再次执行本方法来获得该类的子集集合
                    if (mapItem.getIsParent() == 1){
                        fillChidren(mapItem,sectionTreeSubItemVO,allSectionMap);
                    }
                }
            }
        }
    }

    private SectionTreeItemVO convertListItemToTreeItem(SectionListItemVO listItem){
        return new SectionTreeItemVO()
                .setValue(listItem.getId())
                .setLabel(listItem.getName());
    }

}
